package ms.pay.app.wechat;

import javax.servlet.http.HttpServletRequest;
import java.io.BufferedReader;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;

/**
 * Project Name: ms
 * File Name: WXPay
 * Package Name: ms.pay.app.wechat
 * Date: 2018/5/11  14:43
 * Copyright (c) 2018, tianyul All Rights Reserved.
 * 微信支付
 */
public class WXPay {

    /**
     * 微信统一下单请求交易
     * @param wxPayParam
     */
    public void pay(WXPayParam wxPayParam) {

        try {
            String mch_id = wxPayParam.getMerId();   //商户号
            String notify_url = wxPayParam.getNotifyUrl(); //通知地址  
            String appid = wxPayParam.getAppId();      //应用ID
            String App_Secret = wxPayParam.getAppSecret();
            String nonce_str = WXPayUtil.generateNonceStr();            //随机字符串  
            String sign = "";                   //签名  
            String sign_type = "MD5";                       //签名类型  
            String body = wxPayParam.getBody();                     //商品描述 ps:腾讯充值中心-QQ会员充值
            String out_trade_no = wxPayParam.getOrderId();         //商户订单号
            int total_fee = new BigDecimal(wxPayParam.getAmount()).multiply(new BigDecimal("100")).intValue(); //交易金额
            String spbill_create_ip = "127.0.0.1";//InetAddress.getLocalHost().getHostAddress(); //终端IP
            String trade_type = "APP";          //交易类型  
            String attach = wxPayParam.getAttach();      //附加数据 ps:用户|支付方式

            StringBuffer sb = new StringBuffer();
            sb.append("appid=").append(appid).append("&");
            sb.append("attach=").append(attach).append("&");
            sb.append("body=").append(body).append("&");
            sb.append("mch_id=").append(mch_id).append("&");
            sb.append("notify_url=").append(notify_url).append("&");
            sb.append("nonce_str=").append(nonce_str).append("&");
            sb.append("out_trade_no=").append(out_trade_no).append("&");
            sb.append("sign_type=").append(sign_type).append("&");
            sb.append("spbill_create_ip=").append(spbill_create_ip).append("&");
            sb.append("total_fee=").append(total_fee).append("&");
            sb.append("trade_type=").append(trade_type).append("&");
            String params = sb.toString();
            //需要签名的数据  
            String stringSignTemp = params + "&key=" + App_Secret;
            //MD5签名方式  
            sign = WXPayUtil.MD5(stringSignTemp).toUpperCase();
            Map map = new HashMap<>();
            map.put("appid", appid);
            map.put("attach", attach);
            map.put("body", body);
            map.put("mch_id", mch_id);
            map.put("notify_url", notify_url);
            map.put("nonce_str", nonce_str);
            map.put("out_trade_no", out_trade_no);
            map.put("sign", sign);
            map.put("sign_type", sign_type);
            map.put("spbill_create_ip", spbill_create_ip);
            map.put("total_fee", total_fee);
            map.put("trade_type", trade_type);

            //Httpclient发送请求
            String postResponse = HttpReqUtil.wxpay(map);
            //解析返回的XML数据  
            Map response = WXPayUtil.xmlToMap(postResponse);
            if(!response.isEmpty() && response.get("return_code").equals("SUCCESS")){
                if(response.get("result_code").equals("SUCCESS")) {
                    boolean result = true;

                    if(result) {
                        System.out.println("InfoMsg:--- 微信统一下单请求交易成功");
                    }
                }else {
                    System.out.println("errorMsg:--- 微信统一下单请求交易解析失败");
                }
            }else {
                System.out.println("errorMsg:--- 微信统一下单请求交易解析失败");
            }
            System.out.println("InfoMsg:--- 微信统一下单请求交易结束");
        } catch (Exception e) {
            System.out.println("errorMsg:--- 微信统一下单请求交易失败" + e.getMessage());
        }
    }

    /**
     * 微信异步回调验签
     * @param request
     * @return
     */
    public Map<String,Object> checkSign(HttpServletRequest request, String appId) {
        Map<String,Object> result = new HashMap<>();

        BufferedReader reader = null;
        String wx_map = "";
        try {
            String app_key = appId;
            reader = request.getReader();
            String line = "";
            String xmlString = null;
            StringBuffer inputString = new StringBuffer();
            while ((line = reader.readLine()) != null) {
                inputString.append(line);
            }
            xmlString = inputString.toString();
            request.getReader().close();
            if(!isBlank(xmlString)) {
                Map return_map = WXPayUtil.xmlToMap(xmlString);
                //验签  
                if(WXPayUtil.isSignatureValid(xmlString, app_key)) {
                    if(return_map.get("return_map").equals("SUCCESS")) {
                        String amount = (String) return_map.get("total_fee");
                        String order_no = (String) return_map.get("out_trade_no");
                        result.put("orderId", order_no);
                        result.put("amount", amount);
                        return result;
                    }
                }
            }
            System.out.println("infoMsg:--- 微信异步通知失败");
            return null;
        } catch (Exception e) {
            System.out.println("errorMsg:--- 微信通知失败" + e.getMessage());
            return null;
        }
    }

    /**
     * 微信订单查询
     * @param transactionId  微信订单号
     * @param mchId  商户号
     * @param appId  appid
     * @param appSecret 密钥
     * @param orderId  订单id
     * @return
     */
    public String queryPayOrder(String transactionId, String mchId, String appId, String appSecret, String orderId) {
        String sign = "";
        String message = "";
        Map return_map = null;
        try {
            String mch_id = mchId;   //商户号
            String appid = appId;        //应用ID
            String App_Secret = appSecret;
            String nonce_str = WXPayUtil.generateNonceStr();            //随机字符串  

            StringBuffer sb = new StringBuffer();
            sb.append("appid=").append(appid).append("&");
            sb.append("nonce_str=").append(nonce_str).append("&");
            sb.append("out_trade_no=").append(orderId).append("&");
            String params = sb.toString();
            //需要签名的数据  
            String stringSignTemp = params + "&key=" + App_Secret;
            //MD5签名方式  
            sign = WXPayUtil.MD5(stringSignTemp).toUpperCase();
            Map req_map = new HashMap<>();
            req_map.put("appid", appid);
            req_map.put("mch_id", mch_id);
            req_map.put("transaction_id", transactionId);
            req_map.put("out_trade_no", orderId);
            req_map.put("nonce_str", nonce_str);
            req_map.put("sign", sign);
            String postResponse = HttpReqUtil.queryOrder(req_map);
            if(postResponse.trim().equals("")) {
                return_map = WXPayUtil.xmlToMap(postResponse);
                if(!return_map.isEmpty()) {
                    String return_code = (String) return_map.get("return_code");
                    if(return_code.equals("SUCCESS")) {
                        String result_code = (String) return_map.get("return_code");
                        if(result_code.equals("SUCCESS")) {
                            message = (String) req_map.get("trade_state_desc");
                        }
                    }else {
                        message = (String) req_map.get("err_code_des");
                    }
                }
            }
            System.out.println("infoMsg:--- 微信支付订单查询结束");
        } catch (Exception e) {
            System.out.println("erroroMsg:--- 微信支付订单查询失败" + e.getMessage() + message);
        }
        return message;
    }

    private static boolean isBlank(final CharSequence cs) {
        int strLen;
        if (cs == null || (strLen = cs.length()) == 0) {
            return true;
        }
        for (int i = 0; i < strLen; i++) {
            if (Character.isWhitespace(cs.charAt(i)) == false) {
                return false;
            }
        }
        return true;
    }

}
